Skip to main content

CSS Foundations

Resources

I. Introduction

CSS is made up of various rules, these rules are made up of two important main components:

  • selector
  • declarations (each declaration is made up of a property and value pair)

  • <div> is one of the basic HTML elements, which serves as an empty container. We can use <div> to group our elements.

Adding CSS to HTML

There are three methods to apply CSS styling to HTML elements: external CSS, internal CSS, and inline CSS.

1. External CSS

External CSS is the most common method you will come across, and it involves creating a separate file for the CSS and linking it inside of an HTML’s opening and closing <head> tags with a self-closing <link> element:

<!-- index.html -->
<head>
<link rel="stylesheet" href="styles.css">
</head>
/* styles.css */

div {
color: white;
background-color: black;
}

p {
color: red;
}

→ This method keeps our HTML and CSS separated, which results in the HTML file being smaller and making things look cleaner. We only need to edit the CSS in one place, which is especially handy for websites with many pages that all share similar styles.

2. Internal CSS

Internal CSS involves adding the CSS within the HTML file itself instead of creating a completely separate file. With this method, you place all the CSS code inside a pair of opening and closing <style> tags, which are placed inside the <head> open and closing tags of the HTML file. → We no longer require a <link> element now that the CSS code is in the same file as the HTML code.

<head>
<style>
div {
color: white;
background-color: black;
}

p {
color: red;
}
</style>
</head>
<body>
...
</body>

→ This method can be useful for adding unique styles to a single page of a website, but it doesn’t keep things separate like the external method, and depending on how many rules and declarations there are it can cause the HTML file to get pretty big.

3. Inline CSS

Inline CSS makes it possible to add styles directly to HTML elements, though this method isn’t as recommended. → We’re not using any selectors here, because we’re adding styles directly to HTML elements. We’re adding the CSS code using the style attribute.

<body>
<div style="color: white; background-color: black;">...</div>
</body>

→ This method can get messy for the HTML file once you start adding a lot of CSS declarations to a single element. The method also causes lots of unnecessary repetition of CSS declarations when you want to apply the same style to many different HTML elements.

2. Basic CSS Properties

Resources

1. Color

  • color: sets an element’s text color.
  • background-color: sets an element’s background color.

You can declare the color values using hex, rgb, or hsl color system.

  /* hex example: */
color: #1100ff;

/* rgb example: */
color: rgb(100, 0, 127);

/* hsl example: */
color: hsl(15, 82%, 56%);

2. Typography

  • font-family: determine the font for your web page.
  • font-size: set the size of the font.
  • font-weight: affects the boldness of text.
  • text-align: will align text horizontally within an element.
font-family: "Times New Roman", serif; 
font-size: 22px; /* px is short for pixel, it's an unit */
font-weight: bold;
text-align: center;

3. Image Height and Width

img {
height: auto;
width: 500px;
}

Using the auto value allows the image to not lose it’s proportion (get warped, stretched out). → If an image’s original size was 500px height and 1000px width, using the above CSS would result in a height of 250px.

Note: These <height> and <width> properties work in conjunction with the <height> and width attributes in the HTML. It’s best to include both of these properties and the HTML attributes for image elements, even if you don’t plan on adjusting the values from the image file’s original ones.

3. Selectors

Challenge: CSS Diner

Consider the following index.html file and the style.css examples in each section.

<!-- index.html -->

<div class="greeting">Hello, World!</div>
<div id = "introduction">This is index.html</div>
<p>Hi User!</p>
<div>Okay, bye.</div>

Selectors in CSS are used to target HTML elements for styling. In CSS there are several common selectors that we can use:

1. Universal Selectors

The universal selector will select all HTML elements. For example, the CSS code below applies the color: purple style to every HTML element in the index.html file. The syntax for the universal selector is the symbol: *.

/* styles.css */
* {
color: purple;
}

2. Type Selectors

The type selector (or element selector) will select all elements of the given element type. For example, the CSS code below applies the color: white style to every <div> element in the index.html file, but not any other element (such as <p>). The syntax is just the name of the element.

/* styles.css */

div {
color: white;
}

3. Class Selectors

Class selectors will select all elements with the given class, this class will be determined by us in the HTML file using the following attribute: class = "class-name". In the index.html file, we gave the first <div> element a class called greeting. To style that greeting class, we can use the class selectors. The syntax for class selector is: a period immediately followed by the case-sensitive value of the class attribute.

/* styles.css */

.greeting {
color: red;
}

→ Now, the first <div> with the Hello, World! text will be given color: red styling.

Note: an element can have multiple classes, classes in the class attribute are separate by the whitespace. For example, the following <div> have styling from two classes, greeting and title applied to it.

<!-- index.html -->
<div class="greeting title">Hello, World!</div>
/* styles.css */

.greeting {
color: red;
}

.title{
background-color: green;
}

4. ID Selectors

ID selectors are similar to class selectors. They select an element with the given ID, which is another attribute we place on an HTML element using the following attribute id = "id-name". In the index.html file, we gave the second <div> an id of introduction. The difference between id and classis that en element can only have one ID → avoid giving multiple elements the same ID. The syntax for ID selector is: a hashtag immediately followed by the case-sensitive value of the ID attribute.

/* styles.css */

#introduction {
background-color: red;
}

→ Now, the second <div> will be given a background-color: red styling.

5. Grouping Selectors

What if we have two group of elements that share some style declarations?

.read {
color: white;
background-color: black;
/* several unique declarations */
}

.unread {
color: white;
background-color: black;
/* several unique declarations */
}

To cut down the repetition in .read and .unread class selectors, we can group these two selectors using a comma-separated list. This following block of code works the same as the previous block of code, but it helps reduce repetition in CSS style declarations and allow for easier editing.

.read,
.unread {
color: white;
background-color: black;
}

.read {
/* several unique declarations */
}

.unread {
/* several unique declarations */
}

6. Chaining Selectors

Given the following HTML code. In the following code, there are two elements with the subsection class. However, we only want to apply CSS styling to one of them.

<!-- index.html -->
<div>
<div class="subsection header">Latest Posts</div>
<p class="subsection" id = "preview">This is where a preview for a post might go.</p>
</div>
  • We can apply separate rules to the element by using the chaining selectors. There is no whitespace in the syntax here.
/* styles.css */
.subsection.header {
color: red;
}

/* or */
div.subsection{
color: red;
}

→ What this CSS code does is, it selects any element that has both the subsection and header classes, which is the first <div> element, and apply styling to that element only.

  • We can use chaining selectors to chain a class and an id, there’s also NO whitespace in the syntax here.
/* styles.css */
.subsection#preview {
color: blue;
}

→ Now, this styling only applies to the <p> element, which has both the subsection class and the preview id.

Chaining selectors does not work with type selectors, you cannot chain more than one type selector.

4. Combinators

Combinators allow us to combine multiple selectors. There are four types of combinators.

<main class="parent">
<div class="child group1">
<div class="grand-child group1"></div>
</div>
<div class="child group2">
<div class="grand-child group2"></div>
</div>
<div class="child group3">
<div class="grand-child group3"></div>
</div>
</main>

1. Descendant Combinator

The descendant combinator is represented by a single space character (" ") between two selectors. It allows you to select all the descendants (children, grandchildren, great-grandchildren, etc.) of the first element specified in the selector.

/* Selects all <div> elements inside <main> elements */
main div {
/* Our cool CSS */
}

2. Child Combinator

The child combinator is represented by the ">" symbol between two selectors. It allows you to select only the direct children of the first element specified in the selector.

/* This rule will only select the divs with the class child */
main > div {
/* Our cool CSS */
}

/* This rule will only select the divs with the class grand-child */
main > div > div {
/* More cool CSS */
}

3. Adjacent Sibling Combinator

The adjacent sibling combinator is represented by the "+" symbol between two selectors. It allows you to select all elements that are immediately preceded by the first element specified in the selector.

/* This rule will only select the div with the class child group2 */
.group1 + div {
/* Our cool CSS */
}

/* This rule will only select the div with the class child group3 */
.group1 + div + div {
/* More cool CSS */
}

4. General Sibling Combinator

The general sibling combinator is represented by the "~" symbol between two selectors. It allows you to select all elements that are siblings of the first element specified in the selector, regardless of their position relative to each other.

/* This rule will select all of .group1's siblings - in this case the 2nd and 3rd .child divs */
.group1 ~ div {
/* Our cool CSS */
}

Note: Even though there’s no limit to how many combinators you can add to a rule, we generally want to avoid trying to select elements that need this level of nesting this way.

5. Cascade

The cascade determines what CSS rules get applied to our HTML. There are different factors that the cascade uses to determine this:

1. Specificity

A CSS declaration that is more specific will take precedence over less specific ones. Inline style has the highest specificity compared to selectors. Each type of selector has its own specificity level, which goes in this order: ID selectors (most specific) > class selectors > type selectors.

Specificity is taken into account when a HTML element has multiple conflicting declarations applied to it, it can be understood as a tie-breaker. The style/selector with higher level of specificity will beat others will lower level of specificity.

Example 1 : In this example, both rules are using class selectors, but because rule 2 is more specific (using more class selectors), so the color: red declaration would take precedence.

<!-- index.html -->

<div class="main">
<div class="list subsection">Red text</div>
</div>
/* styles.css */
/* rule 1 */
.subsection {
color: blue;
}

/* rule 2 */
.main .list {
color: red;
}

Example 2: In this example, because rule 1 has the ID selector, which has higher level of specificity, color: blue declaration would take precedence.

<!-- index.html -->

<div class="main">
<div class="list" id="subsection">Blue text</div>
</div>
/* styles.css */
/* rule 1 */
#subsection {
color: blue;
}

/* rule 2 */
.main .list {
color: red;
}

Example 3: This is a more complex example. In this example, neither rule is using a more specific selector than the other. The cascade then checks the number of each selector type. → Because rule 2 has a class selector and an id selector, while rule 1 only has one id selector, rule 2 has higher specificity.

<!-- index.html -->

<div class="main">
<div class="list" id="subsection">Red text</div>
</div>
/* styles.css */
/* rule 1 */
#subsection {
color: blue;
}

/* rule 2 */
.main #subsection {
color: red;
}

When comparing selectors, you may come across special symbols for the universal selector (*) as well as combinators (+~>, and an empty space). These symbols do not add any specificity in and of themselves.

Example 4: Rule 1 uses a chaining selector and Rule 2 uses a descendant combinator, but both rules have two classes and because the combinator symbol doesn’t add any more specificity, these two rules have the same specificity level.

/* styles.css */
/* rule 1 */
.class.second-class {
font-size: 12px;
}

/* rule 2 */
.class .second-class {
font-size: 24px;
}

Example 5: Rule 2 is a type selector, which has the lowest specificity level. However, because * doesn’t have any specificity, rule 2 still takes precedence.

/* rule 1 */
* {
color: black;
}

/* rule 2 */
h1 {
color: orange;
}

2. Inheritance

Inheritance refers to CSS properties that, when applied to a parent element, are inherited by that element’s descendants, even when we don’t write a styling rule for those descendants.

Typography-based properties (color, font-size, font-family, etc.) are usually inherited, while most other properties aren’t.

To apply another style to the descendant elements, all we need to do is directly assign a rule to those elements.

Example: In this example, originally the child element inherited the color: red declaration from parent. To assign a new color to the child element, we directly assign color through a class declaration, as seen in the example.

<!-- index.html -->

<div id="parent">
<div class="child"></div>
</div>
/* styles.css */

#parent {
color: red;
}

.child {
color: blue;
}

→ Despite the parent element having a higher specificity with an ID, the child element would have the color: blue style applied since that declaration directly targets it, while color: red from the parent is only inherited.

3. Rule Order

When every other factor in cascade has been taken into account and there are still conflicting rules targeting an element, cascade determine the “winning” rule by choosing the last defined rule.

Example: The cascade considers specificity (both has class selectors), then inheritance (none here), finally considering rule order. Because rule 2 is declared last, it’s the one that gets applied to the element.

<div id="parent">
<div class="alert warning">I am yellow!</div>
</div>
/* styles.css */

/* rule 1 */
.alert {
color: red;
}

/* rule 2 */
.warning {
color: yellow;
}

II. The Box Model

Resources

Every single element/component on a webpage is a rectangular box, most of the time these boxes are nested within each other, or sitting beside each other.

1. Padding, Margin, Border

Manipulating the size of these boxes and the spaces between them is what helps us positions and style components of our webpages. To do that, we use properties:

  1. padding: the space on all sides between the border of a box and the content inside of the box.

    • To control padding on each side individually, use: padding-top, padding-right, padding-bottom, padding-left.
  2. margin: the invisible space on all sides between borders of a box and borders of adjacent boxes.

    • Margins with positive values push other elements away from the box.
    • Negative values on margin can cause the box to overlap with other boxes.
    • To set the properties of each side individually, use: margin-top, margin-bottom, margin-left, margin-right
    • Margins actually collapse between adjacent box.
      • Two positive margins will combine to become one margin. Its size will be equal to the largest individual margin.
      • Two negative margins will collapse and the smallest (furthest from zero) value will be used.
      • If one margin is negative, its value will be subtracted from the total.

    Example 1: There are two boxes next to each other, one box has a margin: 60px, and the other box also has a margin: 60px, the actual distance between them is collapse to become 60px, not 120px. margin|400 Example 2: If one box has margin: 70px while the other has margin: 60px, the actual distance between them will be 70px, the bigger margin. margin|400

  3. border: adds space on all sides (even if it’s only a pixel or two) between margin and the padding.

    • To set the properties of each side individually, we can use: border-top, border-right, border-bottom, border-left.
    • To set width, style, or colors, use: border-width, border-style, border-color.
    • We can create combinations from the two properties above: border-left-width, border-right-style, border-top-color, etc.

2. Shorthand Property

Shorthand properties which can be used with padding, margin, border, and other values in the box model, allow up to four values, but can accept fewer values.

  1. For padding and margin:
  • If four values are declared, they come in the order: <top>, <right>, <bottom>, <left>.
  • If three values are declared, they come in the order: <top>, <left-right>, <bottom>.
  • If two values care declared, they come in the order: <top-bottom>, <left-right>. Example:
.my-element { 
padding: 10px 20px 10px 20px;
margin: 20px 50px;
}
  1. For border: border: [border-width], [border-style], [border-color]
border: 1px, solid, black; 
border: 2px, dotted, green;

3. Auto and Centering

The value auto tells the browser to define the value for you.

  • Using the auto for width and height means the browser calculates the size of the element based on its content while preserving the aspect ratio or proportion of the content.
  • When margin is set to auto, the browser will automatically distribute the available space equally between the left and right margins. This is often used for centering ***block-level ***elements horizontally. However, auto is NOT helpful when we want to center an element vertically or when centering an inline only element.
.center { 
display: block;
margin-left: auto;
margin-right: auto;
}

Example: These declarations will center the element horizontally within the available space.

  • The element has a block display (either by default or through declarations)
  • The element is given a specified width (not essential to the centering).
  • The left and right margins are set to auto.
.container { 
display: block;
width: 980px;
margin: 0 auto;
/* top-bottom margin: 0px; left-right margin: auto */
}

4. Alternative CSS Box Model

In the Standard CSS Box Model, box-sizing; content-box, when we set properties such as height and width, these values indicate the value of the actual content → content size = total specified dimension. illustration | 600

In the Alternative CSS Box Model, which is achieved when we declare box-sizing: border-box:

  • height and width now takes into account the padding and the border → padding + border + content size = total specified dimension.
  • margin is not accounted into this equation.

illustration | 600

5. Block and Inline

Resources HTML Block and Inline Elements Inline vs Inline-block

CSS has two box types, block and inline. The type refers to how the box behaves in terms of page flow and in relation to other boxes on the page. Boxes have an inner display type and an outer display type.

You can set various values for the display type using the display property. Example: display: block, display: inline.

Block

If a box has an outer display type of block, then:

  • The box will break onto a new line.
  • The width and height properties are respected. (the dimensions we specify are acknowledged and applied)
  • Padding, margin, and border, will cause other elements to be pushed away from the box.
  • If width is not specified, the box will extend in the in

Some HTML elements, such as <h1> and <p>, use block as their outer display type by default.

Example:

<p>I am a paragraph. A short one.</p>

<p>I am another paragraph. Some of the <span class="block">words</span> have been wrapped in a <span class="block">span element</span></p>
p {
border: 2px solid rebeccapurple;
padding: .5em;
}

.block {
display: block;
border: 2px solid blue;
padding: .5em;
}
  • <p> elements has a default display block, so it starts on a new line and extends the entire available width.
  • <span> elements are usually inline, but because we set display: block to the span elements, they all start on a new line and extends the entire available width. illustration | 500

Inline

If a box has outer display type of inline, then:

  • The box will NOT break onto a new line.
  • The width and height properties will not apply. (the dimensions we specify are not considered)
  • Top and bottom padding, margins, and borders will apply but will NOT cause other inline boxes to move away from the box.
  • Left and right padding, margins, and borders will apply and will cause cause other inline boxes to move away from the box.

Some HTML elements, such as <a><span><em> and <strong> use inline as their outer display type by default.

Example:

<p>
I am a paragraph. Some of the
<span>words</span> have been wrapped in a
<span>span element</span>.
</p>

<p class="inline">I am a paragraph. A short one.</p>
<p class="inline">I am another paragraph. Also a short one </p>
p {
border: 2px solid rebeccapurple;
}

span {
border: 2px solid blue;
}

.inline {
display: inline;
}
  • <span> elements have inline display by default, so they don’t force line breaks, they’re continue on the same line.
  • When given the class inline, notice how <p> elements, which used to have default display: block and starts on a new line, now all run together on one line instead of breaking a new one. illustration | 400

Inline-block

display: inline-block is a special value of display, which provides a middle ground between inline and block. We use this property when:

  • We don’t want an item to break onto a new line → inline
  • But we want width and height to be respected, and we want paddding, margin, and border properties to push other elements away from the box. → block

Because the inline-block box doesn’t break onto a new line, when we apply large width and height properties, the content will stay on that same line and grow larger than its container.

Example: <span> element still stays on the same line and doesn’t break onto a new line, but now we can adjust it's width and height properties.

<p>
I am a paragraph and this is a <span class="inline-block">span</span> inside that paragraph. A span is an inline element and so does not respect width and height.
</p>
.inline-block {
display: inline-block;
margin: 20px;
padding: 20px;
width: 50px;
height: 50px;
background-color: lightblue;
border: 2px solid blue;
}